home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / pcr / pcr4_4.lha / DIST / threads / ThreadsTests2.c < prev    next >
C/C++ Source or Header  |  1989-11-30  |  10KB  |  401 lines

  1. /* begincopyright
  2.   Copyright (c) 1988 Xerox Corporation. All rights reserved.
  3.   Use and copying of this software and preparation of derivative works based
  4.   upon this software are permitted. Any distribution of this software or
  5.   derivative works must comply with all applicable United States export
  6.   control laws. This software is made available AS IS, and Xerox Corporation
  7.   makes no warranty about the software, its performance or its conformity to
  8.   any specification. Any person obtaining a copy of this software is requested
  9.   to send their name and post office or electronic mail address to:
  10.     PCR Coordinator
  11.     Xerox PARC
  12.     3333 Coyote Hill Rd.
  13.     Palo Alto, CA 94304
  14.   endcopyright */
  15.  
  16. /*
  17.  * ThreadsTests2.c
  18.  *
  19.  * Demers, November 30, 1989 7:29:16 pm PST
  20.  *
  21.  * Regression tests for gc under threads.
  22.  */
  23.  
  24. #include "xr/Errno.h"
  25. #include "xr/ThreadsBackdoor.h"
  26. #include "xr/GC.h"
  27.  
  28. #include "xr/Threads.h"
  29.  
  30. #ifndef _TIME_
  31. #include <sys/time.h>
  32. #endif
  33.  
  34.  
  35. typedef XR_FinalizationHandle Handle;
  36.  
  37. extern XR_FinalizationQueue XR_NewFQ();
  38. extern Handle XR_NewFinalizationHandle();
  39. extern Handle XR_FQNextNoAbort();
  40.  
  41. /*
  42.  * Parameters
  43.  */
  44.  
  45. int TF_gcInterval = 50;        /* NEWs between forced collections */
  46. int TF_nHeaders = 50;        /* number of pointers held to objects */
  47. int TF_iterations = 10000;    /* number of iterations to run test */
  48.  
  49. /*
  50.  * statistics data structure
  51.  */
  52.  
  53. typedef struct TF_FinalizationStatsRep {
  54.     int fstats_addedToCache;
  55.     int fstats_droppedFromCache;
  56.     int fstats_dequeued;
  57.     int fstats_resurrected;
  58. } * TF_FinalizationStats;
  59.  
  60. static void
  61. TF_PrintStats(i, fstats)
  62.     int i;
  63.     TF_FinalizationStats fstats;
  64. {
  65.     XR_ConsoleMsg("Iter %d: ", i);
  66.     XR_ConsoleMsg("add %d, ", fstats->fstats_addedToCache);
  67.     XR_ConsoleMsg("drop %d, ", fstats->fstats_droppedFromCache);
  68.     XR_ConsoleMsg("dequeue %d, ", fstats->fstats_dequeued);
  69.     XR_ConsoleMsg("resurrect %d\n", fstats->fstats_resurrected);
  70. }
  71.  
  72.  
  73. /*
  74.  * This is a MONITOR!
  75.  */
  76.  
  77. static struct XR_MLRep TF_lock;
  78.  
  79. /*
  80.  * The global finalization queue
  81.  */
  82.  
  83. static XR_FinalizationQueue TF_fq = NIL;
  84.  
  85. /*
  86.  * Failure message printer
  87.  */
  88. static void
  89. TF_Fail(msg, x1, x2, x3, x4)
  90.     char *msg;
  91.     int x1, x2, x3, x4;
  92. {
  93.     XR_ConsoleMsg("Finalization test failed: ");
  94.     XR_ConsoleMsg(msg, x1, x2, x3, x4);
  95.     XR_ConsoleMsg("\n");
  96.     XR_TestFailed("oops!");
  97.     /*NOTREACHED*/
  98. }
  99.  
  100. /*
  101.  * Random numbers
  102.  */
  103.  
  104. extern bool CoinToss();
  105. extern unsigned RandomInRange();
  106.  
  107. #define TF_Random(range) RandomInRange(range)
  108. #define TF_CoinToss() CoinToss()
  109.  
  110. /*
  111.  * Objects
  112.  */
  113.  
  114. typedef struct TFObj {
  115.     int tfo_refCnt;
  116.     int tfo_enabledCnt;
  117.     int tfo_finalizedCnt;
  118.     Handle tfo_hNext;
  119.     Handle tfo_hPrev;
  120.     struct TFObj * tfo_pChild;
  121.     struct TFObj * tfo_pSibling;
  122. };
  123.  
  124.  
  125. static void
  126. TF_InitObj (tfo)
  127.     struct TFObj *tfo;
  128. {
  129.     tfo->tfo_refCnt = 0;
  130.     tfo->tfo_enabledCnt = 0;
  131.     tfo->tfo_finalizedCnt = 0;
  132.     tfo->tfo_hNext = NIL;
  133.     tfo->tfo_hPrev = NIL;
  134.     tfo->tfo_pChild = NIL;
  135.     tfo->tfo_pSibling = NIL;
  136. }
  137.  
  138.  
  139. /*
  140.  * Allocation
  141.  *
  142.  * Doesn't need to be ENTRY because it's okay for numNewCalls to be approximate.
  143.  */
  144.  
  145. static unsigned TF_numNewCalls = 0;
  146.  
  147. static struct TFObj *
  148. TF_NewObj ()
  149. {
  150.     struct TFObj *tfo = (struct TFObj *)XR_malloc(sizeof(struct TFObj));
  151.     TF_InitObj(tfo);
  152.     if( ((++TF_numNewCalls) % TF_gcInterval) == 0 ) XR_GCollect();
  153.     return tfo;
  154. }
  155.  
  156.  
  157. /*
  158.  * Object cache
  159.  *
  160.  * Note the cache contains every object, not every tree of objects.
  161.  */
  162.  
  163. static Handle TF_cache = NIL;
  164.  
  165. static void
  166. TF_AddToCache(h, fstats)
  167.     Handle h;
  168.     TF_FinalizationStats fstats;
  169. {
  170.     struct TFObj *self;
  171.     Handle hNext;
  172.     struct TFObj *next;
  173.     Handle hPrev;
  174.     struct TFObj *prev;
  175.  
  176.     XR_MonitorEntry(&TF_lock);
  177.  
  178.     self = (struct TFObj *) XR_HandleToObject(h);
  179.     if( TF_cache == NIL ) {
  180.         self->tfo_hNext = self->tfo_hPrev = h;
  181.     } else {
  182.         hNext = TF_cache;
  183.         next = (struct TFObj *) XR_HandleToObject(hNext);
  184.         hPrev = next->tfo_hPrev;
  185.         prev = (struct TFObj *) XR_HandleToObject(hPrev);
  186.         self->tfo_hNext = hNext;
  187.         self->tfo_hPrev = hPrev;
  188.         next->tfo_hPrev = h;
  189.         prev->tfo_hNext = h;
  190.     }
  191.     TF_cache = h;
  192.     fstats->fstats_addedToCache += 1;
  193.  
  194.     XR_MonitorExit(&TF_lock);
  195. }
  196.  
  197.  
  198. static void
  199. TF_RemoveFromCache(h, fstats)
  200.     Handle h;
  201.     TF_FinalizationStats fstats;
  202. {
  203.     struct TFObj *self;
  204.     Handle hNext;
  205.     struct TFObj *next;
  206.     Handle hPrev;
  207.     struct TFObj *prev;
  208.  
  209.     XR_MonitorEntry(&TF_lock);
  210.  
  211.     self = (struct TFObj *) XR_HandleToObject(h);
  212.     hNext = self->tfo_hNext;
  213.     hPrev = self->tfo_hPrev;
  214.     if( (hNext == NIL) || (hPrev == NIL) ) TF_Fail("RemoveFromCache botch 1");
  215.     next = (struct TFObj *) XR_HandleToObject(hNext);
  216.     prev = (struct TFObj *) XR_HandleToObject(hPrev);
  217.     if( (next == NIL) || (prev == NIL) ) TF_Fail("RemoveFromCache botch 2");
  218.     self->tfo_hNext = self->tfo_hPrev = NIL;
  219.     if( next != self ) {
  220.         prev->tfo_hNext = hNext;
  221.         next->tfo_hPrev = hPrev;
  222.         TF_cache = hNext;
  223.     } else {
  224.         TF_cache = NIL;
  225.     }
  226.     fstats->fstats_droppedFromCache += 1;
  227.     XR_MonitorExit(&TF_lock);
  228. }
  229.  
  230.  
  231. /*
  232.  * Table of REFs to remembered objects
  233.  */
  234.  
  235. static struct TFObj **TF_remembered = NIL;
  236.  
  237. static void
  238. TF_InitRemembered()
  239. {
  240.     int i;
  241.  
  242.     TF_remembered =
  243.         (struct TFObj **) XR_malloc(TF_nHeaders * sizeof( struct TFObj *));
  244.     for( i = 0; i < TF_nHeaders; i++ ) TF_remembered[i] = NIL;
  245. }
  246.  
  247.  
  248. static void
  249. TF_Remember(tfo)
  250.     struct TFObj * tfo;
  251. {
  252.     struct TFObj * old;
  253.     unsigned i;
  254.  
  255.     XR_MonitorEntry(&TF_lock);
  256.     if( TF_remembered == NIL ) TF_InitRemembered();
  257.     i = TF_Random(TF_nHeaders);
  258.     old = TF_remembered[i];
  259.     TF_remembered[i] = tfo;
  260.     tfo->tfo_refCnt += 1;
  261.     if( old != NIL ) old->tfo_refCnt -= 1;
  262.     XR_MonitorExit(&TF_lock);
  263. }
  264.  
  265.  
  266. static void
  267. TF_ForgetAll()
  268. {
  269.     struct TFObj * tfo;
  270.     unsigned i;
  271.  
  272.     XR_MonitorEntry(&TF_lock);
  273.     if( TF_remembered != NIL ) {
  274.         for( i = 0; i < TF_nHeaders; i++ ) {
  275.             if( (tfo = TF_remembered[i]) != NIL ) {
  276.                 tfo->tfo_refCnt -= 1;
  277.                 TF_remembered[i] = NIL;
  278.             }
  279.         }
  280.         TF_remembered = NIL;
  281.     }
  282.     XR_MonitorExit(&TF_lock);
  283. }
  284.  
  285.  
  286. /*
  287.  * Create random tree
  288.  *
  289.  * Result is finalizable and in cache.
  290.  * It has not been remembered, so its ref cnt is 0, but children's ref counts are nonzero.
  291.  */
  292.  
  293. static struct TFObj *
  294. TF_CreateTree(depth, fstats)
  295.     int depth;
  296.     TF_FinalizationStats fstats;
  297. {
  298.     struct TFObj * root;
  299.     struct TFObj * child;
  300.     Handle h;
  301.     int nChildren;
  302.  
  303.     root = TF_NewObj();
  304.     if( depth >= 3 ) return root;
  305.     for( nChildren = 0; nChildren < 3; nChildren++ ) {
  306.         if( TF_CoinToss() ) break;
  307.     }
  308.     for( ; nChildren > 0; nChildren-- ) {
  309.         child = TF_CreateTree(depth+1, fstats);
  310.         child->tfo_pSibling = root->tfo_pChild;
  311.         root->tfo_pChild = child;
  312.         child->tfo_refCnt += 1;
  313.     }
  314.     h = XR_NewFinalizationHandle();
  315.     root->tfo_enabledCnt += 1;
  316.     XR_EnableFinalization(root, TF_fq, h);
  317.     TF_AddToCache(h, fstats);
  318.     return root;
  319. }
  320.  
  321.  
  322. static unsigned
  323. TF_Finalizer(self)
  324.     XR_MesaProc self;
  325. {
  326.     Handle h;
  327.     struct TFObj * tfo;
  328.     XR_FinalizationState oldState;
  329.     TF_FinalizationStats fstats;
  330.  
  331.     fstats = (TF_FinalizationStats)(self->mp_x);
  332.  
  333.     for(;;) {
  334.         h = XR_FQNextNoAbort(TF_fq);
  335.         if( h == NIL ) return; /* finalizer aborted */
  336.         fstats->fstats_dequeued += 1;
  337.         tfo = (struct TFObj *) XR_HandleToObject(h);
  338.         if( tfo == NIL ) TF_Fail("NIL obj h 0x%x tfo 0x%x", h, tfo);
  339.         if( tfo->tfo_enabledCnt != (tfo->tfo_finalizedCnt+1) )
  340.             TF_Fail("enabledCnt botch ec %d fc %d", tfo->tfo_enabledCnt, tfo->tfo_finalizedCnt);
  341.         if( tfo->tfo_refCnt != 0 )
  342.             TF_Fail("refCnt botch rc %d", tfo->tfo_refCnt);
  343.         tfo->tfo_finalizedCnt += 1;
  344.         if( TF_CoinToss() ) {
  345.             /* resurrect the object */
  346.             oldState = XR_ReenableFinalization(h, TF_fq);
  347.             if( oldState != fzsDisabled )
  348.                 TF_Fail("re-enable oldState botch os %d", oldState);
  349.             tfo->tfo_enabledCnt += 1;
  350.             TF_Remember(tfo);
  351.             fstats->fstats_resurrected += 1;
  352.         } else {
  353.             /* drop the object */
  354.             if( tfo->tfo_pChild != NIL )
  355.                 tfo->tfo_pChild->tfo_refCnt -= 1;
  356.             tfo->tfo_pChild = NIL;
  357.             if( tfo->tfo_pSibling != NIL )
  358.                 tfo->tfo_pSibling->tfo_refCnt -= 1;
  359.             tfo->tfo_pSibling = NIL;
  360.             TF_RemoveFromCache(h, fstats);
  361.         }
  362.     }
  363. }
  364.  
  365.  
  366. void
  367. TestFinalizationWorker()
  368. {
  369.     int i;
  370.     XR_MesaProc mp;
  371.     struct XR_CTRep child;
  372.     TF_FinalizationStats fstats;
  373.  
  374.     TF_fq = XR_NewFQ ();
  375.     fstats =  (TF_FinalizationStats)
  376.     XR_calloc( sizeof(struct TF_FinalizationStatsRep), 1);
  377.  
  378.     XR_ConsoleMsg("Creating finalizer ... ");
  379.     mp = XR_MakeMesaProc(TF_Finalizer, fstats);
  380.     XR_Fork(&child, mp);
  381.     (void)XR_DetachCT(&child);
  382.     XR_ConsoleMsg("ok\n");
  383.  
  384.     XR_ConsoleMsg("Starting %d iterations ...\n", TF_iterations);
  385.     for( i = 0; i < TF_iterations; i++ ) {
  386.         struct TFObj * randomTree;
  387.         if( (i % 1000) == 0 ) TF_PrintStats(i, fstats);
  388.         randomTree = TF_CreateTree(0, fstats);
  389.         TF_Remember(randomTree);
  390.     }
  391.     TF_ForgetAll();
  392.     for( i = 0; ; i++) {
  393.         if( TF_cache == NIL ) break;
  394.         if( i >= 20 ) break;
  395.         XR_GCollect();
  396.         XR_PauseAbortable(XR_MsecToTicks(1000));
  397.     }
  398.     XR_ConsoleMsg("Done.\n");
  399. }
  400.  
  401.